package org.example.protobuf;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;

/**
 * @author hh
 * @since 2024/11/17
 */
public class ProtobufDemo {

    public static void main(String[] args) throws IOException {
//        serAndDser1();
//        serAndDser2();
        serAndDser3();
    }

    /**
     * 序列化与反序列化方式三
     * 带字节长度：[字节长度][字节数据]，用于解决粘包/半包问题
     *
     * 反序列化时，调用Protobuf生成的POJO类的
     * parseDelimitedFrom(InputStream)静态方法，从输入流中先读取
     * varint32类型的长度值，然后根据长度值读取此消息的二进制字节，
     * 再反序列化得到POJO新的实例。
     */
    public static void serAndDser3() throws IOException {
        MsgProto.Msg msg = buildMsg();
        //序列化到二进制流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        msg.writeDelimitedTo(outputStream);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        //从二进制字节流反序列化成ProtoBuf对象
        MsgProto.Msg inMsg = MsgProto.Msg.parseDelimitedFrom(inputStream);
        System.out.println("id = " + inMsg.getId());
        System.out.println("content = " + inMsg.getContent());
    }

    /**
     * 序列化与反序列化方式二
     * 在异步操作的NIO应用场景中存在粘包/半包的问题。
     */
    public static void serAndDser2() throws IOException {
        MsgProto.Msg msg = buildMsg();
        //序列化到二进制流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        msg.writeTo(outputStream);
        ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray());
        //从二进制流反序列化成ProtoBuf对象
        MsgProto.Msg inMsg = MsgProto.Msg.parseFrom(inputStream);
        System.out.println("id = " + inMsg.getId());
        System.out.println("content = " + inMsg.getContent());
    }

    /**
     * 序列化与反序列化方式一
     */
    public static void serAndDser1() throws IOException {
        MsgProto.Msg message = buildMsg();
        //将Protobuf对象序列化成二进制字节数组
        byte[] data = message.toByteArray();
        //可以用于网络传输，保存都内存或外存
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        outputStream.write(data);
        data = outputStream.toByteArray();
        //二进制字节数组反序列化成ProtoBuf对象
        MsgProto.Msg inMsg = MsgProto.Msg.parseFrom(data);
        System.out.println("id = " + inMsg.getId());
        System.out.println("content = " + inMsg.getContent());
    }

    public static MsgProto.Msg buildMsg() {
        MsgProto.Msg.Builder personBuilder = MsgProto.Msg.newBuilder();
        personBuilder.setId(1000);
        personBuilder.setContent("nihao");
        return personBuilder.build();
    }
}
